package traits

import scala.collection.mutable.ArrayBuffer
import model.FichaAnonima
import model.FichaEmpresa
import daos.FichasDAO
import model.EmpresaRegular


trait OperacionesCenso {
  val fichas = FichasDAO
  def fichasAnonimasFiltradas(): ArrayBuffer[FichaAnonima]
  def empresasFiltradas(): ArrayBuffer[EmpresaRegular]
  
  //This is the default implementation.
  def fichasDeEmpresas(): ArrayBuffer[FichaEmpresa] = {
	 this.empresasFiltradas.flatMap(_.fichasE)
   }
    

  
  //	Devuelve el total de ventas en el año sin utilizar un fold
  //RDY
  def totalVentas(): Double = {
    val totalEmpresas = this.fichasDeEmpresas.map(_.montoVentas).sum
    val totalFAnonimas = this.fichasAnonimasFiltradas.map(_.montoVentas).sum
    totalEmpresas + totalFAnonimas
  }

  //	Devuelve el total de ventas en el año utilizando un fold
  //RDY
  def totalVentasFold(): Double = {
    val neutro: Double = 0
    val tE = this.fichasDeEmpresas ++ fichasAnonimasFiltradas
    tE.foldLeft(neutro)({ (t, ficha) => t + ficha.montoVentas })
  }

  //	Devuelve el total de ganancias en el año
  def totalGanancias(): Double = {
    val totalEmpresas = this.fichasDeEmpresas.map(_.montoGanancias).sum
    val totalFAnonimas = this.fichasAnonimasFiltradas.map(_.montoGanancias).sum
    totalEmpresas + totalFAnonimas
  }

  //	Devuelve la cantidad de fichas donde las ventas son mayores al monto dado por parametro
  def fichasConVentasMayoresA(monto: Double): Int = {
    this.filtrarPorCond({ e => e.montoVentas > monto }, { f => f.montoVentas > monto }).size
  }

  //	Devuelve la cantidad de fichas donde las ganancias son mayores al monto dado por parametro
  def fichasConGananciasMayoresA(monto: Double): Int = {
    this.filtrarPorCond({ e => e.montoGanancias > monto }, { f => f.montoGanancias > monto }).size
  }

  //	Devuelve la cantidad de fichas donde la tasa de ganancias es mayor al monto dado por parametro
  def fichasConTasaGananciaMayoresA(monto: Double): Int = {
    this.filtrarPorCond({ e => e.tasaGanancia > monto }, { f => f.tasaGanancia > monto }).size
  }

  //	Devuelve una lista con los nombres de las empresas donde sus ventas son mayores al monto dado por parametro
  def empresasConVentasMayoresA(monto: Double): ArrayBuffer[String] = {
    this.empresasFiltradas.filter(_.fichasE.exists(_.montoVentas > monto)).map(_.nombre)
  }

  def empresasMaxGanancias(): String = {
    this.empresasFiltradas.maxBy(_.fichasE.map(_.montoGanancias).max).nombre
  }

  //	Devuelve una lista con los nombres de las empresas que aportaron al menos una ficha
  def fuentesQueAportaronAlMenosUnaFicha(): ArrayBuffer[String] = {
    (this.fichasAnonimasFiltradas.map(_.fuente.nombre) ++ this.empresasFiltradas.map(_.fuente.nombre)).distinct
  }

  def createMapByProvincia(): Map[String, Double] = {
    val tuplaM = this.empresasFiltradas.map({ e => (e.departamento.provincia.nombre, e.fichasE.map(_.montoVentas).sum) })
    val tuplaFAM = this.fichasAnonimasFiltradas.map({ f => (f.departamento.provincia.nombre, f.montoVentas) })
    (tuplaM ++ tuplaFAM).groupBy(_._1).mapValues({ t => t.map(_._2).sum })
  }

  //Metodos Auxiliares

   private def filtrarPorCond(condE: FichaEmpresa => Boolean, condA: FichaAnonima => Boolean) = {
    this.fichasAnonimasFiltradas.filter(condA) ++ this.fichasDeEmpresas.filter(condE)
  }
  
}
